﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../../global/head.h"
#include "log_file.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace xos_log
{

    log_file::log_file()
    {
        m_nBufNumToFlush = 100;
        m_nYear = 0;
        m_nMonth = 0;
        m_nDay = 0;
        m_nCurHour = 0;
        m_nCurMinute = 0;
    }

    log_file::~log_file()
    {
    }

    ///////////////////////////////////////////////////////////////////////////////////
    // i_log_file方法

    // 
    // 设置日志路径
    // 
    int log_file::set_log_file_path( const char * lpszLogPath )
    {
        int ret = 0;

        if( !lpszLogPath || ( 0 == g_pSysData->m_pContainer->crt()->strlen( lpszLogPath ) ) )
        {
            char path[1024];
            g_pSysData->m_pContainer->misc()->get_process_path( path, sizeof( path ), 0 );
            m_path = path;
        }
        else
        {
            m_path = lpszLogPath;
        }

        {
            ret = create_log_path();
        }

        return ret;
    }

    int log_file::set_buf_num_to_flush( int nBufNum )
    {
        int ret = 0;
        m_nBufNumToFlush = nBufNum;
        return ret;
    }

    // 
    // 输出日志
    // 
    int log_file::out_put_log( i_log_msg * pLogMsg )
    {
        int ret = 0;

        int nYear = 0, nMon = 0, nDay = 0, nHour = 0, nMinute = 0;
        bool bFlush = false;

        {
            pLogMsg->get_log_time( &nYear,
                &nMon,
                &nDay,
                &nHour,
                &nMinute,
                0,
                0 );
        }

        if( m_nCurHour == nHour )
        {
            add_log_to_buf( pLogMsg );
            pLogMsg = 0;
        }

        if( !bFlush && ( m_nCurHour != nHour ) )
        {
            printf( "hour changed : %02d - %02d\r\n", m_nCurHour, nHour );
            bFlush = true;
        }

        if( !bFlush && ( m_nCurMinute != nMinute ) )
        {
            printf( "minute changed : %02d - %02d\r\n", m_nCurMinute, nMinute );
            bFlush = true;
        }

        if( !bFlush && ( ( int )m_log_list.size() >= m_nBufNumToFlush ) )
        {
            printf( "log buf num enough : %d\r\n", ( int )m_log_list.size() );
            bFlush = true;
        }

        if( ( bFlush ) && ( m_log_list.size() > 0 ) )
        {
            printf( "need flush. %04d-%02d-%02d %02d:%02d\r\n", 
                nYear,
                nMon,
                nDay,
                nHour,
                nMinute );
            flush();
        }

        if( bFlush && ( m_nCurMinute != nMinute ) )
        {
            m_nCurMinute = nMinute;
        }

        if( bFlush && ( ( m_nYear != nYear ) || ( m_nMonth != nMon ) || ( m_nDay != nDay ) || ( m_nCurHour != nHour ) ) )
        {
            m_nCurHour = nHour;
            m_nYear = nYear;
            m_nMonth = nMon;
            m_nDay = nDay;
            fmt_file_name();
        }

        if( pLogMsg )
        {
            add_log_to_buf( pLogMsg );
            pLogMsg = 0;
        }

        return ret;
    }

    int log_file::flush()
    {
        int ret = 0;

        xos::i_file * pFile = 0;

        if( ( 0 == ret ) && ( 0 == m_log_list.size() ) )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            ret = g_pSysData->m_pContainer->xos()->create( xos::i_xos::XOS_OBJ_FILE, ( void** )&pFile );
        }

        if( 0 == ret )
        {
            ret = pFile->open( m_full_file.c_str(), xos::i_file::FILE_WRITE, 0, xos::i_file::FILE_CREATE );
        }

        if( 0 == ret )
        {
            ret = pFile->set_file_pos( xos::i_file::FILE_POS_END, 0, 0 );
        }

        // 写入pBuf时确保结尾有0
        for( LOG_ITER iter = m_log_list.begin(); ( 0 == ret ) && ( iter != m_log_list.end() ); ++iter )
        {
            xos_box::i_buf * pBuf = *iter;
            int len = 0;
            const char * lpszLog = pBuf->get_data( 0, 0, &len );
            int r = pFile->write( lpszLog, len );
            if( len != r )
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            printf( "flush log buf num = %d\r\n", ( int )m_log_list.size() );
            m_log_list.put_back_to_pool( true );
        }

        xos_stl::release_interface( pFile );

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int log_file::add_log_to_buf( i_log_msg * pLogMsg )
    {
        int ret = 0;

        const char * lpszLog = 0;
        xos_box::i_buf * pBuf = 0;
        int nBufLen = 0;
        int nLogLen = 0;

        if( 0 == ret )
        {
            lpszLog = pLogMsg->get_log_content( 0, 0, &nLogLen );
        }

        if( 0 != m_log_list.size() )
        {
            pBuf = m_log_list.back();
            pBuf->get_len( &nBufLen );
            nBufLen = xos_box::i_buf::BUF_SIZE - nBufLen;
        }

        // 一条log不可能大地32k, +2是为了写入\r\n
        if( nLogLen + 2 > nBufLen )
        {
            pBuf = g_pSysData->m_pContainer->buf();
            m_log_list.push_back( pBuf );
            nBufLen = xos_box::i_buf::BUF_SIZE;
        }

        pBuf->add_data( lpszLog, nLogLen );
        pBuf->add_data( "\r\n", 2 );

        return ret;
    }

    int log_file::create_log_path()
    {
        int ret = 0;

        xos::i_dir * pDir = 0;

        if( ( 0 == ret ) && m_path.empty() )
        {
            char path[1024];
            g_pSysData->m_pContainer->misc()->get_process_path( path, sizeof( path ), 0 );
            m_path = path;
        }

        if( 0 == ret )
        {
            ret = g_pSysData->m_pContainer->xos()->create( xos::i_xos::XOS_OBJ_DIR, ( void ** )&pDir );
        }

        if( ( 0 == ret ) && ( 0 != pDir->is_dir_exist( m_path.c_str() ) ) )
        {
            ret = pDir->create_directory( m_path.c_str() );
        }

        if( 0 == ret )
        {
            xos::i_time * pTime = g_pSysData->m_pTime;
            pTime->get_time();
            m_nYear = pTime->get_year();
            m_nMonth = pTime->get_month();
            m_nDay = pTime->get_day();
            m_nCurHour = pTime->get_hour();
            m_nCurMinute = pTime->get_minute();
        }

        if( 0 == ret )
        {
            fmt_file_name();
        }

        xos_stl::release_interface( pDir );

        return ret;
    }

    int log_file::fmt_file_name()
    {
        int ret = 0;

        char szFullName[1024];
        char szName[1024];

        if( ( 0 == ret ) && m_path.empty() )
        {
            char path[1024];
            g_pSysData->m_pContainer->misc()->get_process_path( path, sizeof( path ), 0 );
            m_path = path;
        }

        if( 0 == ret )
        {
            g_pSysData->m_pContainer->crt()->sprintf( szName, sizeof( szName ) / sizeof( szName[0] ), "xos_%04d-%02d-%02d-%02d.log",
                m_nYear,
                m_nMonth,
                m_nDay,
                m_nCurHour );
            g_pSysData->m_pContainer->crt()->strcpy( szFullName, sizeof( szFullName ), m_path.c_str() );
            g_pSysData->m_pContainer->misc()->path_append( szFullName, szName );
        }

        if( 0 == ret )
        {
            m_full_file = szFullName;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // for release_impl to use.
    // 

    int log_file::put_back_to_pool( log_file * pT, bool bLock )
    {
        int ret = 0;
        delete pT;
        return ret;
    }

    int log_file::init()
    {
        int ret = 0;
        create_log_path();
        return ret;
    }

    int log_file::term()
    {
        int ret = 0;
        m_log_list.put_back_to_pool( true );
        m_nYear = 0;
        m_nMonth = 0;
        m_nDay = 0;
        m_nCurHour = 0;
        m_nCurMinute = 0;
        return ret;
    }

} // xos_log
